package cn.itrigger.dynamic.sql.where;

import cn.itrigger.dynamic.sql.SqlCriterion;
import cn.itrigger.dynamic.sql.condition.VisitableCondition;
import cn.itrigger.dynamic.sql.structure.BindableColumn;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author admin
 * @date 2018/9/26
 **/
public abstract class AbstractWhereDSL<T extends AbstractWhereDSL<T>> {

    private List<SqlCriterion<?>> criteria = new ArrayList<>();

    protected <S> AbstractWhereDSL(BindableColumn<S> column, VisitableCondition condition) {
        SqlCriterion<S> criterion = SqlCriterion.withColumn(column)
                .withCondition(condition)
                .build();
        criteria.add(criterion);
    }

    protected <S> AbstractWhereDSL(BindableColumn<S> column, VisitableCondition<S> condition, SqlCriterion<?> ... subCriteria) {
        SqlCriterion<S> criterion = SqlCriterion.withColumn(column)
                .withCondition(condition)
                .withSubCriteria(Arrays.asList(subCriteria))
                .build();
        criteria.add(criterion);
    }

    public <S> T and(BindableColumn<S> column, VisitableCondition<S> condition) {
        addCriterion("and", column, condition);
        return getThis();
    }

    public <S> T and(BindableColumn<S> column, VisitableCondition<S> condition, SqlCriterion<?> ... subCriteria) {
        addCriterion("and", column, condition, subCriteria);
        return getThis();
    }

    public <S> T or(BindableColumn<S> column, VisitableCondition<S> condition) {
        addCriterion("or", column, condition);
        return getThis();
    }

    public <S> T or(BindableColumn<S> column, VisitableCondition<S> condition,SqlCriterion<?> ... subCriteria) {
        addCriterion("or", column, condition, subCriteria);
        return getThis();
    }

    private <S> void addCriterion(String connector, BindableColumn<S> column, VisitableCondition<S> condition) {
        SqlCriterion<S> criterion = SqlCriterion.withColumn(column)
                .withConnector(connector)
                .withCondition(condition)
                .build();
        criteria.add(criterion);
    }

    private <S> void addCriterion(String connector, BindableColumn<S> column, VisitableCondition<S> condition,SqlCriterion<?> ... subCriteria) {
        SqlCriterion<S> criterion = SqlCriterion.withColumn(column)
                .withConnector(connector)
                .withCondition(condition)
                .withSubCriteria(Arrays.asList(subCriteria))
                .build();
        criteria.add(criterion);
    }

    protected WhereModel buildWhereModel() {
        return WhereModel.of(criteria);
    }

    protected abstract T getThis();
}
